package algorithm

import (
	"time"

	"b2c-delivery-optimization/internal/model"

	"gorm.io/gorm"
)

// WavePredictor 波次释放时间预测器
type WavePredictor struct {
	// 历史数据权重
	HistoricalWeight float64
	// 订单数量权重
	OrderCountWeight float64
	// 商品数量权重
	ItemCountWeight float64
	// 时间窗口大小（小时）
	TimeWindowSize int
	// 数据库连接
	db *gorm.DB
}

// NewWavePredictor 创建波次预测器实例
func NewWavePredictor(db *gorm.DB) *WavePredictor {
	return &WavePredictor{
		HistoricalWeight: 0.4,
		OrderCountWeight: 0.3,
		ItemCountWeight:  0.3,
		TimeWindowSize:   24,
		db:               db,
	}
}

// PredictReleaseTime 预测波次释放时间
func (p *WavePredictor) PredictReleaseTime(wave *model.Wave, historicalData []model.Wave) time.Time {
	// 1. 计算历史数据预测时间
	historicalTime := p.predictFromHistorical(historicalData)

	// 2. 计算基于订单数量的预测时间
	orderBasedTime := p.predictFromOrderCount(wave)

	// 3. 计算基于商品数量的预测时间
	itemBasedTime := p.predictFromItemCount(wave)

	// 4. 加权平均得到最终预测时间
	totalWeight := p.HistoricalWeight + p.OrderCountWeight + p.ItemCountWeight
	weightedTime := time.Duration(
		float64(historicalTime)*p.HistoricalWeight/totalWeight +
			float64(orderBasedTime)*p.OrderCountWeight/totalWeight +
			float64(itemBasedTime)*p.ItemCountWeight/totalWeight,
	)

	return time.Now().Add(weightedTime)
}

// predictFromHistorical 基于历史数据预测
func (p *WavePredictor) predictFromHistorical(historicalData []model.Wave) time.Duration {
	if len(historicalData) == 0 {
		return 2 * time.Hour // 默认2小时
	}

	// 计算最近TimeWindowSize小时内完成的波次的平均处理时间
	var totalDuration time.Duration
	// 符合条件的波次数量
	count := 0
	// 从当前时间开始往前推TimeWindowSize小时
	cutoffTime := time.Now().Add(-time.Duration(p.TimeWindowSize) * time.Hour)

	for _, wave := range historicalData {
		if wave.Status == model.WaveStatusCompleted && wave.StartTime.After(cutoffTime) {
			duration := wave.EndTime.Sub(wave.StartTime)
			totalDuration += duration
			count++
		}
	}

	if count == 0 {
		return 2 * time.Hour // 默认2小时
	}

	return totalDuration / time.Duration(count)
}

// predictFromOrderCount 基于订单数量预测
func (p *WavePredictor) predictFromOrderCount(wave *model.Wave) time.Duration {
	// 获取波次中的订单数量
	var orderCount int64
	if err := p.db.Model(&model.WaveOrder{}).Where("wave_id = ?", wave.ID).Count(&orderCount).Error; err != nil {
		// 如果查询失败，使用默认值
		orderCount = 1
	}

	// 假设每个订单平均处理时间为30分钟
	baseTime := 30 * time.Minute
	// 考虑订单数量对处理时间的影响（非线性增长）
	// 因为多个订单会产生资源冲突竞争现象
	orderFactor := 1.0 + float64(orderCount-1)*0.1
	return time.Duration(float64(baseTime) * orderFactor)
}

// predictFromItemCount 基于商品数量预测
func (p *WavePredictor) predictFromItemCount(wave *model.Wave) time.Duration {
	// 获取波次中所有订单的商品总数
	var totalItems int64
	if err := p.db.Model(&model.WaveOrder{}).
		Joins("JOIN orders ON wave_orders.order_id = orders.id").
		Where("wave_orders.wave_id = ?", wave.ID).
		Select("COALESCE(SUM(orders.total_items), 0)").
		Scan(&totalItems).Error; err != nil {
		// 如果查询失败，使用默认值
		totalItems = 1
	}

	// 假设每个商品平均处理时间为5分钟
	baseTime := 5 * time.Minute
	// 考虑商品数量对处理时间的影响（非线性增长）
	// 因为多个商品会产生资源冲突竞争现象
	itemFactor := 1.0 + float64(totalItems-1)*0.05
	return time.Duration(float64(baseTime) * itemFactor)
}

// UpdateWeights 更新预测权重
func (p *WavePredictor) UpdateWeights(historicalWeight, orderCountWeight, itemCountWeight float64) {
	p.HistoricalWeight = historicalWeight
	p.OrderCountWeight = orderCountWeight
	p.ItemCountWeight = itemCountWeight
}

// SetTimeWindowSize 设置时间窗口大小
func (p *WavePredictor) SetTimeWindowSize(hours int) {
	p.TimeWindowSize = hours
}
